define([ 'util/JQuery', 'util/Knockout', 'domain/Game', 'domain/Card', 'renderer/Renderer', 'util/ArrayUtil', 'util/Timer', 'util/Initializer' ], function($, ko, Game, Card, Renderer, arrayUtil,
		Timer, Initializer) {
	'use strict';
	var model = function(gameId, initUI) {
		var self = this;

		// attributes
		self.game = new Game(gameId);

		self.initUI = initUI;

		// private attributes
		var renderer = new Renderer();

		var initializer = new Initializer("Game");

		var loadTimer = new Timer();

		self.call = function(card) {
			if (self.game.usableCard(card)) {
				$(".hand").addClass("call");
				$.post("{0}/call/{1}/{2}".format(self.game.gameId, card.type, card.suit)).success(startFetchinState);
			}
		};

		self.pass = function() {
			$.post("{0}/pass".format(self.game.gameId)).success(startFetchinState);
		};

		var finish = function() {
			$.get("{0}/finish".format(self.game.gameId)).success(function(summaryJSON) {
				console.log(summaryJSON);
			});
		};

		var load = function() {
			$.get("{0}/state".format(self.game.gameId)).success(convertToGame);
		};

		// Converter methods
		var convertToGame = function(gameJSON) {

			$(".hand").removeClass("call");

			stopFetchinState();

			var card = convertToCardArray(gameJSON.t).last();

			var actions = gameJSON.a;

			if (initializer.initialized() && actions.contains('OPPONENT_CALLED')) {
				renderer.callOpponent(card);
			}

			if (initializer.initialized() && actions.contains('CALLED')) {
				renderer.callPlayer(card);
			}

			setStateFromJSON(gameJSON);

			if (initializer.initialized() && actions.contains('HIT')) {
				renderer.turnWon(ko.utils.arrayMap(self.game.table(), function(card) {
					return card.cardClassSelector();
				}));
			}

			if (initializer.initialized() && actions.contains('LOST')) {
				renderer.turnLost(ko.utils.arrayMap(self.game.table(), function(card) {
					return card.cardClassSelector();
				}));
			}

			initializer.init(firstInit);

			if (self.game.finished()) {
				renderer.render(finish);
			} else {
				renderer.render(startFetchinState);
			}
		};

		var setStateFromJSON = function(gameJSON) {
			self.game.deckSize(gameJSON.dS);
			self.game.myCall(gameJSON.c);
			self.game.possiblePass(gameJSON.p);
			self.game.finished(gameJSON.f);
			self.game.timeExpWarning(gameJSON.tEW);

			arrayUtil.arrayExecuteChanges(self.game.opponentHand, convertToCardArray(createCards(gameJSON.oHC)));
			arrayUtil.arrayExecuteChanges(self.game.hand, convertToCardArray(gameJSON.h));
			arrayUtil.arrayExecuteChanges(self.game.table, convertToCardArray(gameJSON.t));
		};

		var createCards = function(count) {
			var opponentHandCards = [];
			for ( var i = 0; i < count; i++) {
				opponentHandCards.push(new Card(new String(i), new String(i), false));
			}

			return opponentHandCards;
		};

		var convertToCardArray = function(cardsJSON) {
			if (cardsJSON == null) {
				return [];
			}

			return $.map(cardsJSON, function(item) {
				return convertToCard(item);
			});
		};

		var convertToCard = function(cardJSON) {
			return new Card(cardJSON.type, cardJSON.suit, cardJSON.usable);
		};

		var startFetchinState = function() {
			loadTimer.start(load, 1000);
		};

		var stopFetchinState = function() {
			loadTimer.stop();
		};

		var firstInit = function() {
			renderer.refreshTable(self.game.table());
			initUI();
		};

		// main
		// First load
		load();

		// Start timers
		startFetchinState();

	};

	return model;

});
